package org.agony2d.gpu.core {
	import flash.geom.Point;
	
	import org.agony2d.core.agony_internal;
	import org.agony2d.gpu.effects.EffectAA;
	import org.agony2d.gpu.supportClasses.ContainerAABase;
	
	use namespace agony_internal;
	
	/** [ BranchAA ] - abstract
	 *  [◆]
	 *  	1.  numNodes
	 *  [◆◆]
	 *  	1.  addNode
	 *  	2.  addNodeAt
	 *  	3.  getNodeAt
	 *  	4.  getNodeIndex
	 *  	5.  setNodeIndex
	 *  	6.  swapNodes
	 *  	7.  swapNodesAt
	 *  	8.  removeAllNodes
	 */
	/** dirty: vertexChanged × altered */
public class BranchAA extends ContainerAABase {
	
	public function BranchAA() {
		m_altered = true
	}
	
	final public function get numNodes() : int {
		return m_numNodes
	}
	
	public function addNode( node:NodeAA ) : void {
		node.attach(this)
		m_nodeList[m_numNodes++] = node
	}
	
	/** splice index参数...
	 *  等同于:
	 *  if(index < 0) {
	 *  	index = arr.length + index
	 *  }
	 *  if(index < 0) {
	 *  	index = 0
	 *  }
	 *  else if(index > arr.length) {
	 *  	index = arr.length
	 *  }
	 *  (为负时，为倒序插入，超过length时自动缩回...)
	 */
	public function addNodeAt( node:NodeAA, index:int ) : void {
		node.attach(this)
		m_nodeList.splice(index, 0, node)
		m_numNodes++
	}
	
	public function getNodeAt( index:int ) : NodeAA {
		var A:Object
		
		A = m_nodeList[index]
		return (A is EffectAA) ? A.m_targetNode : A as NodeAA
	}
	
	public function getNodeIndex( node:NodeAA ) : int {
		return m_nodeList.indexOf(node)
	}
	
	public function setNodeIndex( node:NodeAA, index:int ) : void {
		var oldIndex:int
		
		oldIndex = m_nodeList.indexOf(node)
		if (oldIndex != index) {
			m_nodeList.splice(oldIndex, 1)
			m_nodeList.splice(index, 0, node)
		}
	}
	
	public function swapNodes( node_A:Object, node_B:Object ) : void {
		var index_A:int, index_B:int
		
		index_A = m_nodeList.indexOf(node_A)
		index_B = m_nodeList.indexOf(node_B)
		this.swapNodesAt(index_A, index_B)
	}
	
	public function swapNodesAt( indexA:int, indexB:int ) : void {
		var node:Object
		
		if (indexA != indexB) {
			node                =  m_nodeList[indexA]
			m_nodeList[indexA]  =  m_nodeList[indexB]
			m_nodeList[indexB]  =  node
		}
	}
	
	public function removeAllNodes() : void {
		var i:int
		
		while (i < m_numNodes) {
			m_nodeList[i++].dispose()
		}
		m_nodeList.length = m_numNodes = 0
	}
	
	override public function globalToLocal( globalX:Number, globalY:Number, result:Point = null ) : Point {
		if (!result) {
			result = new Point
		}
		this.doUpdateUpward()
		cachedMatrix.invert()
		result.setTo(cachedMatrix.a * globalX + cachedMatrix.c * globalY + cachedMatrix.tx, cachedMatrix.d * globalY + cachedMatrix.b * globalX + cachedMatrix.ty)
		return result	
	}
	
	override public function localToGlobal( localX:Number, localY:Number, result:Point = null ) : Point {
		if (!result) {
			result = new Point
		}
		this.doUpdateUpward()
		result.setTo(cachedMatrix.a * localX + cachedMatrix.c * localY + cachedMatrix.tx, cachedMatrix.d * localY + cachedMatrix.b * localX + cachedMatrix.ty)
		return result		
	}
	

	agony_internal var m_nodeList:Array = []
	agony_internal var m_numNodes:int
	

	
	override agony_internal function dispose() : void {
		var i:int
		
		this.removeAllListeners()
		while (i < m_numNodes) {
			m_nodeList[i++].dispose()
		}
	}
		
	override agony_internal function removeNode( node:NodeAA ) : void {
		var index:int
		
		index = m_nodeList.indexOf(node)
		m_nodeList.splice(index, 1)
		--m_numNodes
	}
	
	[Inline]
	final override agony_internal function checkCollisionNode( globalX:Number, globalY:Number, forInteract:Boolean ) : NodeAA {
		var node:NodeAA
		var l:int
		
		if (forInteract && m_intouchable) {
			return null
		}
		if (m_collisionMethod != null) {
			this.doTransformToLocal(globalX, globalY)
			return m_collisionMethod(cachedPoint.x, cachedPoint.y, this) ? this : null
		}
		l = m_numNodes
		while (--l > -1) {
			node = m_nodeList[l]
			node = node.checkCollisionNode(globalX, globalY, forInteract)
			if (node) {
				return node
			}
		}
		return null
	}
	
	[Inline]
	final override agony_internal function doTransformToLocal( x:Number, y:Number ) : void {
		cachedMatrix.copyFrom(m_matrix_B)
		cachedMatrix.invert()
		cachedPoint.setTo(cachedMatrix.a * x + cachedMatrix.c * y + cachedMatrix.tx, cachedMatrix.d * y + cachedMatrix.b * x + cachedMatrix.ty)
	}
	
	//[Inline]
	final agony_internal function doExtractNodes( vertexChanged:Boolean ) : void {
		var i:int
		
		m_cachedAlpha = m_alpha * m_parent.m_alpha
		if (vertexChanged) {
			if (m_altered) {
				this.doUpdateDownward()
				m_altered = false
			}
			else {
				m_matrix_B.copyFrom(m_matrix_A)
			}
			m_matrix_B.concat(m_parent.m_matrix_B)
		}
		else if (m_altered) {
			this.doUpdateDownward()
			m_altered = false
			m_matrix_B.concat(m_parent.m_matrix_B)
			vertexChanged = true
		}
		while ((m_numNodes - i) % 8) {
			m_nodeList[i++].render(vertexChanged)
		}
		while (i < m_numNodes) {
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
			m_nodeList[i++].render(vertexChanged)
		}
	}
	
}
}